package Dashboard;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

/**
 * This class contains the dashboard itself, with all the gauges and buttons
 * 
 * @author Sietse
 * 
 */
public class MainViewPanel extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 2216335185329217557L;

	// The dashboard image itself
	private BufferedImage dashboardImage;

	// Initialize the tilt gauge
	private BufferedImage tiltGaugeImage;
	private BufferedImage tiltGaugeNeedle;
	private BufferedImage tiltGaugeWarning;

	// Initialize the sail gauge
	private BufferedImage sailGaugeImage;
	private BufferedImage sailGaugeSailNeedle;
	private BufferedImage sailGaugeWindNeedle;
	private BufferedImage sailGaugeWarning;

	// Initialize the rudder gauge
	private BufferedImage rudderGaugeImage;
	private BufferedImage rudderGaugeNeedle;
	private BufferedImage rudderGaugeWarning;

	// Initialize the bluetooth and replay indicator lights
	private BufferedImage bluetoothConnection;
	private BufferedImage replayFunction;

	// Initialize the button images
	private BufferedImage buttonGreenOff;
	private BufferedImage buttonGreenOn;
	private BufferedImage buttonRedOff;
	private BufferedImage buttonRedOn;
	private BufferedImage warningRedOff;
	private BufferedImage warningRedOn;
	private BufferedImage warningGreenOff;
	private BufferedImage warningGreenOn;

	// Initialize the button texts
	private BufferedImage controlAutomatic;
	private BufferedImage controlManual;

	private BufferedImage keelUp;
	private BufferedImage keelDown;
	private BufferedImage motorForward;
	private BufferedImage motorBackward;
	private BufferedImage motorNeutral;
	private BufferedImage emergencySituation;
	private BufferedImage emergencyStop;

	// Initialize the needle rotations
	private double tiltNeedleRotation;
	private double sailNeedleRotation;
	private double windNeedleRotation;
	private double rudderNeedleRotation;

	/**
	 * Loads the images and sets the default values
	 */
	public MainViewPanel() {

		this.setDoubleBuffered(true);
		this.setOpaque(true);

		initImages();
		initButtonLights();

		this.setOpaque(true);

		tiltNeedleRotation = 0.0;
		sailNeedleRotation = 0.0;
		windNeedleRotation = 0.0;
		rudderNeedleRotation = 0.0;

	}

	/**
	 * Loads all required images
	 */
	private void initImages() {
		dashboardImage = this.loadImage("/Resources/Images/dashboardMain.gif");

		tiltGaugeImage = this
				.loadImage("/Resources/Images/gaugeTiltSmallBackground.gif");
		tiltGaugeNeedle = this
				.loadImage("/Resources/Images/gaugeTiltSmallNeedle.gif");

		sailGaugeImage = this
				.loadImage("/Resources/Images/gaugeSailSmallBackground.gif");
		sailGaugeSailNeedle = this
				.loadImage("/Resources/Images/gaugeSailSmallSailNeedle.gif");
		sailGaugeWindNeedle = this
				.loadImage("/Resources/Images/gaugeSailSmallWindNeedle.gif");

		rudderGaugeImage = this
				.loadImage("/Resources/Images/gaugeRudderSmallBackground.gif");
		rudderGaugeNeedle = this
				.loadImage("/Resources/Images/gaugeRudderSmallNeedle.gif");

		buttonGreenOff = this.loadImage("/Resources/Images/buttonGreenOff.gif");
		buttonGreenOn = this.loadImage("/Resources/Images/buttonGreenOn.gif");
		buttonRedOff = this.loadImage("/Resources/Images/buttonRedOff.gif");
		buttonRedOn = this.loadImage("/Resources/Images/buttonRedOn.gif");

		warningRedOff = this
				.loadImage("/Resources/Images/buttonRedOffSmall.gif");
		warningRedOn = this.loadImage("/Resources/Images/buttonRedOnSmall.gif");
		warningGreenOff = this
				.loadImage("/Resources/Images/buttonGreenOffSmall.gif");
		warningGreenOn = this
				.loadImage("/Resources/Images/buttonGreenOnSmall.gif");

	}

	/**
	 * Sets the button lights on their default value
	 */
	private void initButtonLights() {
		// set default value warning lights
		tiltGaugeWarning = warningRedOff;
		sailGaugeWarning = warningRedOff;
		rudderGaugeWarning = warningRedOff;

		bluetoothConnection = warningGreenOff;
		replayFunction = warningGreenOff;

		// set default value control buttons
		controlAutomatic = buttonGreenOff;
		controlManual = buttonGreenOff;
		keelUp = buttonGreenOff;
		keelDown = buttonGreenOff;
		motorForward = buttonGreenOff;
		motorBackward = buttonGreenOff;
		motorNeutral = buttonGreenOff;
		emergencySituation = buttonRedOff;
		emergencyStop = buttonRedOff;

	}

	/**
	 * A custom (manual) paint method with offsets
	 * 
	 * @param g
	 *            the Graphics it needs to paint on
	 * @param startX
	 * @param startY
	 */
	public void paintM(Graphics g, int startX, int startY) {
		// Draw background
		int x, y;
		x = startX;
		y = startY;
		g.drawImage(this.dashboardImage, x, y, null);

		// Draw tilt gauge
		x += 150;
		y += 100;
		g.drawImage(this.tiltGaugeImage, x, y, null);
		g.drawImage(this.paintGaugeNeedle(this.tiltGaugeNeedle,
				this.tiltNeedleRotation), x, y, null);

		x += 90;
		y += 210;
		g.drawImage(this.tiltGaugeWarning, x, y, null);

		// drawBluetooth + replay
		y = startY + 70;
		g.drawImage(this.bluetoothConnection, x, y, null);
		x += 250;
		g.drawImage(this.replayFunction, x, y, null);

		// Draw sail position + WindDirection Gauge
		x = startX + 400;
		y = startY + 100;
		g.drawImage(this.sailGaugeImage, x, y, null);
		g.drawImage(this.paintGaugeNeedle(this.sailGaugeSailNeedle,
				this.sailNeedleRotation), x, y, null);
		g.drawImage(this.paintGaugeNeedle(this.sailGaugeWindNeedle,
				this.windNeedleRotation), x, y, null);

		x += 90;
		y += 210;
		g.drawImage(this.sailGaugeWarning, x, y, null);

		// Draw rudder position gauge
		x = startX + 650;
		y = startY + 100;
		g.drawImage(this.rudderGaugeImage, x, y, null);
		g.drawImage(this.paintGaugeNeedle(this.rudderGaugeNeedle,
				this.rudderNeedleRotation), x, y, null);

		x += 90;
		y += 210;
		g.drawImage(this.rudderGaugeWarning, x, y, null);

		// Draw ControlImages
		x = startX + 150;
		y = startY + 400;
		g.drawImage(controlAutomatic, x, y, null);
		y = startY + 460;
		g.drawImage(controlManual, x, y, null);
		y = startY + 520;

		// Draw KeelImages
		x = startX + 325;
		y = startY + 400;
		g.drawImage(keelUp, x, y, null);
		y = startY + 460;
		g.drawImage(keelDown, x, y, null);

		// Draw MotorImages
		x = startX + 500;
		y = startY + 400;
		g.drawImage(motorForward, x, y, null);
		y = startY + 460;
		g.drawImage(motorNeutral, x, y, null);
		y = startY + 520;
		g.drawImage(motorBackward, x, y, null);

		// Draw EmergencyImages
		x = startX + 675;
		y = startY + 400;
		g.drawImage(emergencySituation, x, y, null);
		y = startY + 460;
		g.drawImage(emergencyStop, x, y, null);

	}

	/**
	 * Sets the control buttons lights to the given value
	 * 
	 * @param control
	 *            the value the lights need to be set to
	 */
	public void setControlButton(int control) {
		switch (control) {
		case 0:
			controlAutomatic = buttonGreenOff;
			controlManual = buttonGreenOn;
			break;
		case 1:
			controlAutomatic = buttonGreenOn;
			controlManual = buttonGreenOff;
			break;
		default:
			controlAutomatic = buttonGreenOff;
			controlManual = buttonGreenOff;
			break;
		}
	}

	/**
	 * Sets the keel buttons lights to the given value
	 * 
	 * @param keel
	 *            the value the lights need to be set to
	 */
	public void setKeelButton(int keel) {
		switch (keel) {
		case 0:
			keelUp = buttonGreenOn;
			keelDown = buttonGreenOff;
			break;
		case 1:
			keelUp = buttonGreenOff;
			keelDown = buttonGreenOn;
			break;
		default:
			keelUp = buttonGreenOff;
			keelDown = buttonGreenOff;
			break;
		}
	}

	/**
	 * Sets the motor buttons lights to the given value
	 * 
	 * @param motor
	 *            the value the lights need to be set to
	 */
	public void setMotorButton(int motor) {
		switch (motor) {
		case 0:
			// Motor Achteruit
			motorForward = buttonGreenOff;
			motorNeutral = buttonGreenOff;
			motorBackward = buttonGreenOn;
			break;
		case 1:
			// Motor Neutraal
			motorForward = buttonGreenOff;
			motorNeutral = buttonGreenOn;
			motorBackward = buttonGreenOff;
			break;
		case 2:
			// Motor Vooruit
			motorForward = buttonGreenOn;
			motorNeutral = buttonGreenOff;
			motorBackward = buttonGreenOff;
			break;
		default:
			motorForward = buttonGreenOff;
			motorNeutral = buttonGreenOff;
			motorBackward = buttonGreenOff;
			break;
		}
	}

	/**
	 * Sets the light of the emergencysituation button
	 * 
	 * @param emergencySituation
	 *            the value the light needs to be set to
	 */
	public void setEmergencySituationButton(int emergencySituation) {
		switch (emergencySituation) {
		case 0:
			this.emergencySituation = buttonRedOff;
			break;
		case 1:
			this.emergencySituation = buttonRedOn;
			// this.emergencyStop = buttonRedOff;
			break;
		default:
			this.emergencySituation = buttonRedOff;
			break;
		}
	}

	/**
	 * Sets the light of the emergencystop button
	 * 
	 * @param emergencyStop
	 *            the value the light needs to be set to
	 */
	public void setEmergencyStopButton(int emergencyStop) {
		switch (emergencyStop) {
		case 0:
			this.emergencyStop = buttonRedOff;
			break;
		case 1:
			this.emergencyStop = buttonRedOn;
			// this.emergencySituation = buttonRedOff;
			break;
		default:
			this.emergencyStop = buttonRedOff;
			break;
		}
	}

	/**
	 * Loads an image from the given path
	 * 
	 * @param path
	 *            the location of the image
	 * @return a BufferedImage with the given image
	 */
	public BufferedImage loadImage(String path) {
		BufferedImage img = null;
		try {
			img = ImageIO.read(getClass().getResource(path.toString()));
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		return img;
	}

	/**
	 * Sets the light of the bluetooth connection indicator
	 * 
	 * @param value
	 *            the value the light needs to be set to
	 */
	public void setBluetoothConnection(int value) {
		switch (value) {
		case 1:
			bluetoothConnection = warningGreenOn;
			break;
		default:
			bluetoothConnection = warningGreenOff;
			break;
		}
	}

	/**
	 * Sets the light of the replay indicator
	 * 
	 * @param value
	 *            the value the light needs to be set to
	 */
	public void setReplayFunction(int value) {
		switch (value) {
		case 1:
			replayFunction = warningGreenOn;
			break;
		default:
			replayFunction = warningGreenOff;
			break;
		}
	}

	/**
	 * Sets the rotation of the rudder needle
	 * 
	 * @param rotation
	 *            the rotation in degrees
	 */
	public void setRudderNeedleRotation(int rotation) {
		this.rudderNeedleRotation = Math.toRadians(rotation);
		if (rotation < 100 || rotation > 260) {
			rudderGaugeWarning = warningRedOn;
		} else {
			rudderGaugeWarning = warningRedOff;
		}
	}

	/**
	 * Sets the rotation of the tilt needle
	 * 
	 * @param rotation
	 *            the rotation in degrees
	 */
	public void setTiltNeedleRotation(int rotation) {
		this.tiltNeedleRotation = Math.toRadians(rotation);
		if (rotation < 120 || rotation > 210)
			tiltGaugeWarning = warningRedOn;
		else
			tiltGaugeWarning = warningRedOff;
	}

	/**
	 * Sets the rotation of the wind direction needle
	 * 
	 * @param rotation
	 *            the rotation in degrees
	 */
	public void setWindNeedleRotation(int rotation) {
		this.windNeedleRotation = Math.toRadians(rotation);
	}

	/**
	 * Sets the rotation of the sail needle
	 * 
	 * @param rotation
	 *            the rotation in degrees
	 */
	public void setSailNeedleRotation(int rotation) {
		this.sailNeedleRotation = Math.toRadians(rotation);
		if (rotation < 90 || rotation > 270)
			sailGaugeWarning = warningRedOn;
		else
			sailGaugeWarning = warningRedOff;
	}

	/**
	 * Rotates the given needle image
	 * 
	 * @param needle
	 *            the needle image
	 * @param rotation
	 *            the rotation in degrees
	 * @return the rotated needle
	 */
	private BufferedImage paintGaugeNeedle(BufferedImage needle, double rotation) {
		int width = needle.getWidth();
		int heigth = needle.getHeight();

		// Create a simple copy of the needle
		BufferedImage needleCopy = new BufferedImage(width, heigth, needle
				.getColorModel().getTransparency());

		Graphics2D g2D = needleCopy.createGraphics(); // Get the Graphics2D from
														// the copy
		g2D.rotate(rotation, width / 2, heigth / 2); // Rotate the Graphics2D
		g2D.drawImage(needle, 0, 0, null); // Draw the original needle onto the
											// Graphics2D
		g2D.dispose();

		return needleCopy;
	}
}
